package jnpf.engine.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import groovy.lang.GroovyShell;
import jnpf.engine.custom.constants.BasicActivitiConstants;
import jnpf.engine.entity.FlowTemplateEntity;
import jnpf.engine.entity.FlowTemplateJsonEntity;
import jnpf.engine.enums.FlowNodeTypeEnum;
import jnpf.engine.model.flowengine.shuntjson.childnode.ChildNode;
import jnpf.engine.model.flowengine.shuntjson.childnode.CounterSign;
import jnpf.engine.model.flowengine.shuntjson.childnode.FlowAssignModel;
import jnpf.engine.model.flowengine.shuntjson.childnode.Properties;
import jnpf.engine.model.flowengine.shuntjson.nodejson.ChildNodeList;
import jnpf.exception.WorkFlowException;
import jnpf.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.groovy.control.MultipleCompilationErrorsException;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.xerial.snappy.Snappy;

import java.io.IOException;
import java.util.*;

import static jnpf.engine.custom.constants.BasicActivitiConstants.exActivitiPrefixURL;
import static jnpf.engine.custom.constants.BasicActivitiConstants.extensionAttributeName;
import static org.flowable.engine.impl.bpmn.behavior.CallActivityBehavior.CALLED_ELEMENT_TYPE_KEY;

/**
 * @author LoveMyOrange
 * @create 2021-09-20 19:09
 * @desc 动态创建 Activiti 流程图对象
 */
@SuppressWarnings("all")
@Slf4j
public class BpmnModelUtils {

    private ThreadLocal<List<SequenceFlow>> sequenceFlowList = new ThreadLocal();
    public static BpmnModel setBpmnModelInfo(BpmnModel bpmnModel, FlowTemplateEntity flowEngineEntity){
        bpmnModel.setTargetNamespace(flowEngineEntity.getCategory());//这行代码没用 任性...
        bpmnModel.addNamespace(BasicActivitiConstants.exActivitiPrefix, BasicActivitiConstants.exActivitiPrefixURL);
        return bpmnModel;
    }
    public  static Process createProcess(FlowTemplateJsonEntity flowTemplateJsonEntity, FlowTemplateEntity flowTemplateEntity){
        Process process = new Process();
        process.setId(BasicActivitiConstants.activitiPrefix+flowTemplateJsonEntity.getGroupId());//
        process.setName(flowTemplateEntity.getFullName());
        process.setExecutable(true);
        process.setDocumentation(flowTemplateEntity.getDescription());
        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        jnpf.engine.assembly.GlobalExPropertyDTO bpmnExPropertyDTO=new jnpf.engine.assembly.GlobalExPropertyDTO();
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
        bpmnExPropertyDTO.setFlowCategory(flowTemplateEntity.getCategory());
        bpmnExPropertyDTO.setFlowType(flowTemplateEntity.getType());
        bpmnExPropertyDTO.setFlowTemplateJson(flowTemplateJsonEntity.getFlowTemplateJson());
        bpmnExPropertyDTO.setFlowTemplateJsonId(flowTemplateJsonEntity.getId());
        bpmnExPropertyDTO.setFlowTemplateId(flowTemplateEntity.getId());
            String str = JsonZipUtil.zipString(JsonUtil.getObjectToString(bpmnExPropertyDTO));
            extensionAttribute.setValue(str);
        process.addAttribute(extensionAttribute);
        return process;
    }

    public static StartEvent createStartEvent(Process process){
        StartEvent startEvent = new StartEvent();
        startEvent.setId(BasicActivitiConstants.startEventId);
        startEvent.setName("流程启动");
        startEvent.setInitiator(BasicActivitiConstants.startEventInitiator);//发起人
        startEvent.setDocumentation("流程启动");
        process.addFlowElement(startEvent);
        return startEvent;
    }







    public static  void setCounterSignInfo(UserTask userTask, Properties properties){
        MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics= new MultiInstanceLoopCharacteristics();
        String id = userTask.getId();
        multiInstanceLoopCharacteristics.setInputDataItem(id+"assigneeList");//collection属性
        multiInstanceLoopCharacteristics.setElementVariable("assignee");
        multiInstanceLoopCharacteristics.setSequential(false);//不管是 或签还是会签 都是并行会签
        userTask.setAssignee("${assignee}");
        Integer counterSign = properties.getCounterSign();
        //如果是或签 那么设置一下完成条件 只有会签中的任何一个人完成  那么都算会签完成了
        if(counterSign==0){
            //完成的会签实例数 除 总会签实例数 >0
            multiInstanceLoopCharacteristics.setCompletionCondition("${counterSignCompleteFlag}");
//            multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances > 0}");
        }
        else if(counterSign==1){
            CounterSign counterSignConfig = properties.getCounterSignConfig();
            Integer auditNum = counterSignConfig.getAuditNum();
            Integer auditRatio = counterSignConfig.getAuditRatio();
            Integer auditType = counterSignConfig.getAuditType();
            if(FlowNature.RejectNo.equals(auditType)){

            }
            else if(FlowNature.RejectNumber.equals(auditType)){
                multiInstanceLoopCharacteristics.setCompletionCondition("${auditNum > "+auditNum+"}");
            }
            else if(FlowNature.RejectPercent.equals(auditType)){
                //会签完成比例
                String strRate=auditRatio+"";
                Double rate = Double.valueOf(strRate);
                rate=rate/100;
                multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances >= "+rate+"}");
            }

        }
        else {
            multiInstanceLoopCharacteristics.setSequential(true);
        }
        userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
    }
    public static  void setCallActivityCounterSignInfo(CallActivity callActivity, Properties properties){
        MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics= new MultiInstanceLoopCharacteristics();
        String id = callActivity.getId();
        multiInstanceLoopCharacteristics.setInputDataItem(id+"assigneeList");//collection属性
        multiInstanceLoopCharacteristics.setElementVariable("assignee");
//        multiInstanceLoopCharacteristics.setSequential(false);//不管是 或签还是会签 都是并行会签
//        Integer counterSign = properties.getCounterSign();
//        Long countersignRatio = properties.getCountersignRatio();
//        //如果是或签 那么设置一下完成条件 只有会签中的任何一个人完成  那么都算会签完成了
//        if(counterSign==0){
//            //完成的会签实例数 除 总会签实例数 >0
//            multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances > 0}");
//        }
//        else if(counterSign==1){
//            //会签完成比例
//            String strRate=countersignRatio+"";
//            Double rate = Double.valueOf(strRate);
//            rate=rate/100;
//            multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances >= "+rate+"}");
//        }
//        else {
//            multiInstanceLoopCharacteristics.setSequential(true);
//        }
        callActivity.setLoopCharacteristics(multiInstanceLoopCharacteristics);
    }


    /**
     * 创建调用活动
     */
    public static String createCallActivity(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        CallActivity callActivity=new CallActivity();
        callActivity.setId(childNode.getNodeId());
        callActivity.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        callActivity.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());
        String flowId = childNode.getProperties().getFlowId();
        jnpf.engine.assembly.CallActivityExPropertyDTO callActivityExPropertyDTO=new jnpf.engine.assembly.CallActivityExPropertyDTO();
//
//        FlowEngineService flowEngineService = SpringContextHolder.getBean(FlowEngineService.class);
//        FlowEngineEntity flowEngineEntity = flowEngineService.getById(flowId);
//        String enCode = flowEngineEntity.getEnCode();
//        String processDefinitionKey=BasicActivitiConstants.activitiPrefix+enCode;
//        callActivity.setCalledElement(processDefinitionKey);
        callActivity.setCalledElementType(CALLED_ELEMENT_TYPE_KEY);
        callActivity.setInheritBusinessKey(false);
        //
        FlowableListener flowableListener = new FlowableListener();
        flowableListener.setEvent(ExecutionListener.EVENTNAME_START);
        flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
        flowableListener.setImplementation("#{callActivityStartedListener}");

        List<FlowableListener> flowableListenerList=new ArrayList<>();
        flowableListenerList.add(flowableListener);
        callActivity.setExecutionListeners(flowableListenerList);
        List<FlowAssignModel> assignList = properties.getAssignList();

        List<String> parentFields=new ArrayList<>();
        List<String> subFields=new ArrayList<>();
        List<IOParameter> ioParameterList=new ArrayList<>();
//        for (FlowAssignModel flowAssignModel : assignList) {
//           IOParameter ioParameter=new IOParameter();
//           ioParameter.setSource(flowAssignModel.getParentField());
//           ioParameter.setTarget(flowAssignModel.getChildField());
//           ioParameterList.add(ioParameter);
//        }
        callActivity.setInParameters(ioParameterList);
        callActivityExPropertyDTO.setIsAsync(properties.getIsAsync());
//        callActivityExPropertyDTO.setMessageType(properties.getMessageType());
        callActivityExPropertyDTO.setLaunchMsgConfig(properties.getLaunchMsgConfig());
        callActivityExPropertyDTO.setAssignList(assignList);
        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
        extensionAttribute.setValue(JSONObject.toJSONString(callActivityExPropertyDTO));
        callActivity.addAttribute(extensionAttribute);
        process.addFlowElement(callActivity);
        return callActivity.getId();
    }

    /**
     * 创建抄送节点
     * @param fromId
     * @param childNode
     * @param process
     * @param sequenceFlowList
     * @param childNodeList
     * @return
     */
    public static String createManualTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        ManualTask manualTask=new ManualTask();
        manualTask.setId(childNode.getNodeId());
        manualTask.setName(childNode.getContent());
        Properties properties = childNode.getProperties();
        manualTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());



//        List<String> circulatePosition = properties.getCirculatePosition();
//        List<String> circulateRole = properties.getCirculateRole();
        List<String> circulateUser = properties.getCirculateUser();
//        List<String> to = properties.getTo();
//        String from = properties.getFrom();
//        String subject = properties.getSubject();
//        List<String> cc = properties.getCc();
//        List<String> bcc = properties.getBcc();
//        String html = properties.getHtml();
//        Boolean processFlag = properties.getProcessFlag();
//        String notifyContent = properties.getNotifyContent();


        String type = childNode.getType();
        jnpf.engine.assembly.ManualTaskExPropertyDTO manualTaskExPropertyDTO=new jnpf.engine.assembly.ManualTaskExPropertyDTO();
        manualTaskExPropertyDTO.setType(childNode.getType());
        if(FlowNodeTypeEnum.COPY.getType().equals(type)){
//            manualTaskExPropertyDTO.setCirculatePosition(circulatePosition);
//            manualTaskExPropertyDTO.setCirculateRole(circulateRole);
            manualTaskExPropertyDTO.setCirculateUser(circulateUser);
        }
        else if(FlowNodeTypeEnum.MAIL.getType().equals(type)){
//            manualTaskExPropertyDTO.setTo(to);
//            manualTaskExPropertyDTO.setFrom(from);
//            manualTaskExPropertyDTO.setCc(cc);
//            manualTaskExPropertyDTO.setBcc(bcc);
//            manualTaskExPropertyDTO.setHtml(html);
//            manualTaskExPropertyDTO.setSubject(subject);
//            manualTaskExPropertyDTO.setMailFiles(properties.getFileList());
        }
        else if(FlowNodeTypeEnum.DING.getType().equals(type)
        || FlowNodeTypeEnum.WX.getType().equals(type)
        || FlowNodeTypeEnum.DX.getType().equals(type)
        || FlowNodeTypeEnum.ZHAN.getType().equals(type)
        ){
//            manualTaskExPropertyDTO.setTo(to);
//            manualTaskExPropertyDTO.setProcessFlag(processFlag);
//            manualTaskExPropertyDTO.setNotifyContent(notifyContent);
        }
        else{
            throw new WorkFlowException("不支持此类型的节点");
        }

        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);
        extensionAttribute.setValue(JSONObject.toJSONString(manualTaskExPropertyDTO));
        manualTask.addAttribute(extensionAttribute);
        process.addFlowElement(manualTask);
        return manualTask.getId();
    }



    public static String createSwerveServiceTask(String fromId, Process process,Map<String,ChildNode> conditionNodeList,String sequenceFlowId){
        ManualTask serviceTask=new ManualTask();
        serviceTask.setId(id(BasicActivitiConstants.SWERVE_TASK_PREFIX));
        serviceTask.setName("转向节点");
        serviceTask.setDocumentation("转向节点"+ BasicActivitiConstants.taskDescriptionSeparator+"转向"+ BasicActivitiConstants.taskDescriptionSeparator+"转向");

        ChildNode childNode = conditionNodeList.get(sequenceFlowId);
        Properties properties = childNode.getProperties();
        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        extensionAttribute.setNamespacePrefix(jnpf.engine.custom.constants.BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(jnpf.engine.custom.constants.BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(jnpf.engine.custom.constants.BasicActivitiConstants.exActivitiPrefixURL);

        properties.setNodeType(FlowNodeTypeEnum.SWERVE_TASK.getType());
        String ex = JsonUtil.getObjectToString(properties);
        String str = JsonZipUtil.zipString(ex);
        extensionAttribute.setValue(str);
        serviceTask.addAttribute(extensionAttribute);
        process.addFlowElement(serviceTask);
        return serviceTask.getId();
    }
    private static String id(String prefix) {
        return prefix + "-" + UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }

    public static String createScriptTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
        ScriptTask scriptTask=new ScriptTask();
//        scriptTask.setId(childNode.getNodeId());
//        scriptTask.setName(childNode.getContent());
//        Properties properties = childNode.getProperties();
//        scriptTask.setDocumentation(childNode.getContent()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getDescription()+ BasicActivitiConstants.taskDescriptionSeparator+properties.getTitle());
//
//        Integer scriptFormat = properties.getScriptFormat();
//        String scriptContent = properties.getScriptContent();
//        scriptTask.setScriptFormat(FlowScriptTypeEnum.getMessageByIndex(scriptFormat));
//
//        if(scriptFormat==1){
//            boolean b = grammarCheck(scriptContent);
//            if(!b){
//                throw  new WorkFlowException("编写的Groovy脚本有问题,请重试");
//            }
//        }
//        scriptTask.setScript(scriptContent);
//        process.addFlowElement(scriptTask);
        return scriptTask.getId();
    }




    public static boolean grammarCheck(String exp) {
        try {
            new GroovyShell().parse(exp);
            return true;
        } catch(MultipleCompilationErrorsException cfe) {
            return false;
        }
    }

    public static boolean isURL(String str){
        //转换为小写
        str = str.toLowerCase();
        String regex = "^((https|http|ftp|rtsp|mms)?://)" //https、http、ftp、rtsp、mms
                + "?(([0-9a-z_!~*‘().&=+$%-]+: )?[0-9a-z_!~*‘().&=+$%-]+@)?" //ftp的user@
                + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如：199.194.52.184
                + "|" // 允许IP和DOMAIN(域名)
                + "([0-9a-z_!~*‘()-]+\\.)*" // 域名- www.
                + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名
                + "[a-z]{2,6})" // first level domain- .com or .museum
                + "(:[0-9]{1,5})?" // 端口号最大为65535,5位数
                + "((/?)|" // a slash isn‘t required if there is no file name
                + "(/[0-9a-z_!~*‘().;?:@&=+$,%#-]+)+/?)$";
        return str.matches(regex);
    }

    public static boolean isJSON(String str) {
        boolean result = false;
        try {
            Object obj= JSON.parse(str);
            result = true;
        } catch (Exception e) {
            result=false;
        }
        return result;
    }









    public static  String createReceiveTask(String fromId, ChildNode childNode, Process process, List<SequenceFlow> sequenceFlowList, ChildNodeList childNodeList){
            ReceiveTask receiveTask = new ReceiveTask();
            Properties properties = childNode.getProperties();
            receiveTask.setId(childNode.getNodeId());
            receiveTask.setName(properties.getTitle());
            receiveTask.setDocumentation(properties.getDescription());

        ExtensionAttribute extensionAttribute = new ExtensionAttribute();
        jnpf.engine.assembly.ReceiveTaskExPropertyDTO activityExPropertyDTO =new jnpf.engine.assembly.ReceiveTaskExPropertyDTO();
        extensionAttribute.setNamespacePrefix(BasicActivitiConstants.exActivitiPrefix);
        extensionAttribute.setName(BasicActivitiConstants.extensionAttributeName);
        extensionAttribute.setNamespace(BasicActivitiConstants.exActivitiPrefixURL);

//        Integer types = properties.getTypes();
//        if(types!=null){
//            if(0==types){
//                Integer day = properties.getDay();
//                Integer hour = properties.getHour();
//                Integer minute = properties.getMinute();
//                Integer second = properties.getSecond();
//                Integer totalSecond=day*24*60*60;
//                totalSecond+=hour*60*60;
//                totalSecond+=minute*60;
//                totalSecond+=second;
//                activityExPropertyDTO.setTotalSeconds(totalSecond);
//            }
//            else{
//                activityExPropertyDTO.setFormFieldNameEx(properties.getFormFieldNameEx());
//            }
//        }
//        else{
//            Integer day = properties.getDay();
//            Integer hour = properties.getHour();
//            Integer minute = properties.getMinute();
//            Integer second = properties.getSecond();
//            Integer totalSecond=day*24*60*60;
//            totalSecond+=hour*60*60;
//            totalSecond+=minute*60;
//            totalSecond+=second;
//            activityExPropertyDTO.setTotalSeconds(totalSecond);
//        }
//            extensionAttribute.setValue(JSONObject.toJSONString(activityExPropertyDTO));
//            receiveTask.addAttribute(extensionAttribute);
//            process.addFlowElement(receiveTask);
            return receiveTask.getId();
    }


    public static EndEvent createEndEvent(){
        EndEvent endEvent = new EndEvent();
        endEvent.setId(BasicActivitiConstants.endEventId);
        endEvent.setName("流程结束");
        endEvent.setDocumentation("流程结束");
        return endEvent;
    }

    /**
     * 添加一条入线
     * @param source
     * @param incomingFlow
     */
    public static  void addInComingFlow(FlowElement source, SequenceFlow incomingFlow){
        List<SequenceFlow> sequenceFlows = null;
        if (source instanceof Task) {
            sequenceFlows = ((Task) source).getIncomingFlows();
        } else if (source instanceof Gateway) {
            sequenceFlows = ((Gateway) source).getIncomingFlows();
        } else if (source instanceof SubProcess) {
            sequenceFlows = ((SubProcess) source).getIncomingFlows();
        } else if (source instanceof StartEvent) {
            sequenceFlows = ((StartEvent) source).getIncomingFlows();
        } else if (source instanceof EndEvent) {
            sequenceFlows = ((EndEvent) source).getIncomingFlows();
        }
        //
        for (SequenceFlow sequenceFlow : sequenceFlows) {
            if(incomingFlow.getId().equals(sequenceFlow.getId())){
                continue;
            }
            sequenceFlows.add(sequenceFlow);
        }
    }

    /**
     * 添加一条出线
     * @param source
     * @param outgoingFlow
     */
    public static void addOutgoingFlow(FlowElement source, SequenceFlow outgoingFlow) {
        List<SequenceFlow> sequenceFlows = null;
        if (source instanceof Task) {
            sequenceFlows = ((Task) source).getOutgoingFlows();
        } else if (source instanceof Gateway) {
            sequenceFlows = ((Gateway) source).getOutgoingFlows();
        } else if (source instanceof SubProcess) {
            sequenceFlows = ((SubProcess) source).getOutgoingFlows();
        } else if (source instanceof StartEvent) {
            sequenceFlows = ((StartEvent) source).getOutgoingFlows();
        } else if (source instanceof EndEvent) {
            sequenceFlows = ((EndEvent) source).getOutgoingFlows();
        }
        //
        for (SequenceFlow sequenceFlow : sequenceFlows) {
            if(outgoingFlow.getId().equals(sequenceFlow.getId())){
                continue;
            }
            sequenceFlows.add(sequenceFlow);
        }
    }

    /**
     *
     * @param id
     */
    public <T extends FlowElement> FlowElement getFlowElement(String id, Process process){
        FlowElement source = process.getFlowElement(id);
        if (source instanceof Task) {
            source = ((Task) source);
        } else if (source instanceof Gateway) {
            source = ((Gateway) source);
        } else if (source instanceof SubProcess) {
            source = ((SubProcess) source);
        } else if (source instanceof StartEvent) {
            source = ((StartEvent) source);
        } else if (source instanceof EndEvent) {
            source = ((EndEvent) source);
        }
        return source;
    }


    public Boolean isMultiInstance(FlowElement flowElement){
        if(flowElement instanceof UserTask){
            UserTask userTask=(UserTask)flowElement;
            return userTask.hasMultiInstanceLoopCharacteristics();
        }
        else{
            return false;
        }
    }

    public static Map<String,Object> getFirstNodeFormData(String definitionId,String businessKey){
        RepositoryService repositoryService = SpringContextHolder.getBean(RepositoryService.class);
        FlowTaskUtil flowTaskUtil = SpringContextHolder.getBean(FlowTaskUtil.class);
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        Process mainProcess = bpmnModel.getMainProcess();
        FlowElement targetFlowElement = mainProcess.findFlowElementsOfType(StartEvent.class).get(0).getOutgoingFlows().get(0).getTargetFlowElement();
        String property = getAttributeValueByTaskDefinitionKey(mainProcess, targetFlowElement.getId(), "userTask");
        Properties properties = JSONObject.parseObject(property, new TypeReference<Properties>() {
        });
        Map<String, Object> map = flowTaskUtil.infoData(properties.getFormId(), businessKey);
        return map;
    }

    public static Properties getFirstNodeProperty(String definitionId){
        RepositoryService repositoryService = SpringContextHolder.getBean(RepositoryService.class);
        FlowTaskUtil flowTaskUtil = SpringContextHolder.getBean(FlowTaskUtil.class);
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        Process mainProcess = bpmnModel.getMainProcess();
        FlowElement targetFlowElement = mainProcess.findFlowElementsOfType(StartEvent.class).get(0).getOutgoingFlows().get(0).getTargetFlowElement();
        String property = getAttributeValueByTaskDefinitionKey(mainProcess, targetFlowElement.getId(), "userTask");
        Properties properties = JSONObject.parseObject(property, new TypeReference<Properties>() {
        });
        return properties;
    }

    public static UserTask getFirstUserTaskNode(String definitionId){
        RepositoryService repositoryService = SpringContextHolder.getBean(RepositoryService.class);
        FlowTaskUtil flowTaskUtil = SpringContextHolder.getBean(FlowTaskUtil.class);
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        Process mainProcess = bpmnModel.getMainProcess();
        FlowElement targetFlowElement = mainProcess.findFlowElementsOfType(StartEvent.class).get(0).getOutgoingFlows().get(0).getTargetFlowElement();
        return (UserTask) targetFlowElement;
    }

    public static Process getBpmnModelMainProcess(String processDefinitionId){
        RepositoryServiceImpl repositoryService = SpringContextHolder.getBean(RepositoryServiceImpl.class);
        return repositoryService.getBpmnModel(processDefinitionId).getMainProcess();
    }

    private static String getSnappyUnComPress(String zip){
        try {
            return new String(Snappy.uncompress(zip.getBytes()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public  static List<FlowElement> getAllElementsWithNoUsed(Process process){
        List<FlowElement> flowElementList= new ArrayList<>();
        Collection<FlowElement> flowElements = process.getFlowElements();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof SequenceFlow|| flowElement instanceof ExclusiveGateway ||flowElement instanceof ParallelGateway ||
                    flowElement instanceof InclusiveGateway || flowElement instanceof CallActivity  || flowElement instanceof StartEvent){
                continue;
            }
            else {
                flowElementList.add(flowElement);
            }
        }
        return flowElementList;
    }
    public static String getAttributeValueByTaskDefinitionKey(Process process, String taskDefinitionKey, String nodeType){
        FlowElement flowElement = process.getFlowElement(taskDefinitionKey);
         if("global".equals(nodeType)){
            String property = process.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
            property = property.replace(" ", "\r\n");
            property=JsonZipUtil.unzipString(property);
            return property;
        }
        else{
             String property = flowElement.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
             property = property.replace(" ", "\r\n");
             property=JsonZipUtil.unzipString(property);
             return property;
        }
    }

    public static Properties getElementProperty(FlowElement flowElement){
        String property = flowElement.getAttributeValue(exActivitiPrefixURL, extensionAttributeName);
        property = property.replace(" ", "\r\n");
        property=JsonZipUtil.unzipString(property);
        Properties properties = JSONObject.parseObject(property, new TypeReference<Properties>() {});
        return properties;
    }

    public static Properties getElementProperty(Process process){
        UserTask startUserTask = getFirstNode(process);
        Properties elementProperty = getElementProperty(startUserTask);
        return elementProperty;
    }

    /**
     * 获取当前节点是否为发起节点
     * @param process
     * @param taskDefinitionKey
     * @return
     */
    public static Boolean getIsStartEvent(Process process,String taskDefinitionKey){
        if (taskDefinitionKey.isEmpty() || null == process){
            return false;
        }
        Collection<FlowElement> flowElements = process.getFlowElements();
        for (FlowElement flowElement : flowElements) {
            if (flowElement instanceof StartEvent) {
                SequenceFlow sequenceFlow = ((StartEvent) flowElement).getOutgoingFlows().get(0);
                if (sequenceFlow.getTargetRef().equals(taskDefinitionKey)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 在本系统中starEvent必定只有一条连线且 目标节点必定是userTask
     * @param process
     * @return
     */
    public static UserTask getFirstNode(Process process){
        return (UserTask)((StartEvent)process.getInitialFlowElement()).getOutgoingFlows().get(0).getTargetFlowElement();
    }

    /**
     * 获取Process中 除了连线的元素
     * @param process
     * @return
     */
    public static List<FlowElement> getFlowElementsWithOutSequenceFlow(Process process){
        List<FlowElement> finalElements=new ArrayList<>();
        Collection<FlowElement> flowElements = process.getFlowElements();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof SequenceFlow){

            }
            else if(flowElement instanceof StartEvent){

            }
            else{
               finalElements.add(flowElement);
            }
        }
        return finalElements;
    }

    public static FlowNode getFlowNodeById(Process process, String nodeId){
            return (FlowNode) process.getFlowElement(nodeId);
    }
    public static FlowElement getStartFlowElement(Collection<FlowElement> flowElements) {
        for (FlowElement flowElement : flowElements) {
            if (flowElement instanceof StartEvent) {
                return flowElement;
            }
        }
        return null;
    }

    public static FlowElement getFlowElementById(String Id, Collection<FlowElement> flowElements) {
        for (FlowElement flowElement : flowElements) {
            if (flowElement.getId().equals(Id)) {
                //如果是子任务，则查询出子任务的开始节点
                if (flowElement instanceof SubProcess) {
                    return getStartFlowElement(((SubProcess) flowElement).getFlowElements());
                }
                return flowElement;
            }
            if (flowElement instanceof SubProcess) {
                FlowElement flowElement1 = getFlowElementById(Id, ((SubProcess) flowElement).getFlowElements());
                if (flowElement1 != null) {
                    return flowElement1;
                }
            }
        }
        return null;
    }
    public static FlowElement getSubProcess(Collection<FlowElement> flowElements, FlowElement flowElement) {
        for (FlowElement flowElement1 : flowElements) {
            if (flowElement1 instanceof SubProcess) {
                for (FlowElement flowElement2 : ((SubProcess) flowElement1).getFlowElements()) {
                    if (flowElement.equals(flowElement2)) {
                        return flowElement1;
                    }
                }
            }
        }
        return null;
    }


}
